package miniproj.simulators.simulator2;

import java.util.*;

import miniproj.config.Config;
import miniproj.exception.IncorrectDateFormatException;
import miniproj.models.people.*;
import miniproj.models.reservation.Date;
import miniproj.models.reservation.Reservation;
import miniproj.models.reservation.Schedule;
import miniproj.models.room.Room;
import miniproj.models.groups.*;
import miniproj.services.data.DataContext;
import miniproj.services.util.SimulatorHelper;

/**
 * 
 * Client de gestion de l'edt permettant a un enseignant responsable d'un
 * enseignement de gerer les seances de cet enseignement, d'affecter/modifier
 * les enseignants intervenant dans les seances, les groupes d'etudiants qui
 * suivent l'enseignement et l'edt de l'enseignement.
 * 
 * @author Thibault PIKETTY
 * 
 */
public class Simulator {

	private DataContext dc;

	private Scanner scanner;
	private Teaching t;

	/**
	 * Instantiates a new simulator.
	 */
	public Simulator() {
		this.dc = DataContext.getDataContext();
		this.scanner = new Scanner(System.in);
	}

	/**
	 * Load data.
	 */
	public void loadData() {
		dc.loadFromFile(Config.SERIALIZATION_FOLDER_PATH,
				Config.SERIALIZATION_DATACONTEXT_FILE_NAME);
		System.out.println("Data loaded from DataContext file.");
	}

	private void saveData() {
		dc.saveInFile(Config.SERIALIZATION_FOLDER_PATH,
				Config.SERIALIZATION_DATACONTEXT_FILE_NAME);
		System.out.println("Les donnees ont ete enregistrees.");
		this.menu();
	}

	/**
	 * Launch ui.
	 */
	public void launchUI() {
		this.identification();
	}

	private void identification() {
		System.out.println("*** Identification ***");
		System.out.println("Entrer votre nom ou uniquement \"q\" pour quitter");
		String lastName = this.scanner.nextLine();

		if (lastName.equals("q"))
			return;

		System.out
				.println("Entrer votre prenom ou uniquement \"q\" pour quitter");
		String firstName = this.scanner.nextLine();

		if (firstName.equals("q"))
			return;

		t = this.selectTeaching(firstName, lastName);

		if (t == null) {
			System.out
					.println("Votre nom ne correspond � aucun responsable d'enseignement. Veuillez retaper votre nom.");
			this.identification();
		} else {
			this.menu();
		}
	}

	private Teaching selectTeaching(String firstName, String lastName) {
		LinkedList<Teaching> teachings = Teaching
				.getTeachingsByHeadTeacherName(firstName, lastName,
						this.dc.getTeachings());

		if (teachings.size() == 0)
			return null;

		System.out
				.println("Selectionner le numero de l'enseignement dont vous etes responsable ou uniquement \"q\" pour quitter : ");

		int i = 1;
		for (Teaching smth : teachings) {
			System.out.println(i + ") " + smth.getName());
			i++;
		}
		String input = scanner.nextLine();

		if (input.equals("q")) {
			return null;
		}

		int reponse;
		try {
			reponse = Integer.parseInt(input);
		} catch (Exception e) {
			System.err.println("an internal error as occured : ");
			e.printStackTrace();
			return this.selectTeaching(firstName, lastName);
		}

		if (reponse > 0 && reponse <= teachings.size())
			return teachings.get(reponse - 1);
		else {
			System.out.println("Choix invalide");
			return selectTeaching(firstName, lastName);
		}
	}

	private void modifierNomEnseignement() {
		String newNom;
		System.out
				.println("Entrez le nouveau nom ou uniquement \"q\" pour revenir au menu principal : ");

		scanner = new Scanner(System.in);
		newNom = scanner.nextLine();

		if (newNom.equals("q")) {
			this.menu();
			return;
		} else {
			t.setName(newNom);
		}
		menu();
	}

	private void addGroup() {
		System.out
				.println("Choisissez le numero du groupe que vous souhaitez ajouter ou uniquement \"0\" pour revenir au menu principal : ");

		LinkedList<Group> unusedGroups = new LinkedList<Group>();

		for (Group p : this.dc.getGroups())
			if (!t.getStudentsGroups().contains(p) && !unusedGroups.contains(p))
				unusedGroups.add(p);

		int reponse2;
		Iterator<Group> it = unusedGroups.iterator();
		int j = 1;

		while (it.hasNext()) {
			System.out.println(j + ") " + it.next().getId());
			j++;
		}

		System.out.println("Entrez le numero du groupe qui vous interesse : ");
		reponse2 = Integer.parseInt(scanner.next());

		if (reponse2 == 0) {
			this.menu();
			return;
		}
		;

		if (reponse2 > 0 && reponse2 <= unusedGroups.size())
			t.getStudentsGroups().addLast((unusedGroups.get(reponse2 - 1)));

		menu();
	}

	private void deleteGroup() {
		System.out
				.println("Choisissez le numero du groupe que vous souhaitez enlever ou uniquement \"0\" pour revenir au menu principal : ");

		int reponse2;
		Iterator<Group> it = t.getStudentsGroups().iterator();
		int j = 1;

		while (it.hasNext()) {
			System.out.println(j + ") " + it.next().getId());
			j++;
		}

		System.out.println("Entrez le numero du groupe qui vous interesse : ");
		reponse2 = Integer.parseInt(scanner.next());

		if (reponse2 == 0) {
			this.menu();
			return;
		}

		if (reponse2 > 0 && reponse2 <= this.dc.getGroups().size())
			t.getStudentsGroups().remove(
					(this.dc.getGroups().get(reponse2 - 1)));

		menu();
	}

	private void addSeance() {
		System.out.println("*** Effectuer une reservation ***");
		System.out
				.println("Entrer une date de reservation (format JJ/MM/AAAA) ou uniquement \"q\" pour revenir au menu principal.)");

		String input = this.scanner.next();

		if (input.equals("q")) {
			this.menu();
			return;
		}

		String terms[] = input.split("/");

		if (terms.length != 3) {
			System.out
					.println("Mauvaise saisie. Veuillez reeffectuer la saisie.\n");
			this.addSeance();
			return;
		}

		int day, month, year;
		try {
			day = Integer.parseInt(terms[0]);
			month = Integer.parseInt(terms[1]);
			year = Integer.parseInt(terms[2]);
		} catch (Exception e) {
			System.out.println("Saisie incorrecte. Veuillez reessayer.\n");
			this.addSeance();
			return;
		}

		this.addSeance1(year, month, day);
	}

	private void addSeance1(int year, int month, int day) {
		System.out.println("Veuillez choisir un creneau :");
		System.out.println("1) Matin 1 (8:00 - 10:00)");
		System.out.println("2) Matin 2 (10:15 - 12:15)");
		System.out.println("3) Apres-midi 1 (13:30 - 15:30)");
		System.out.println("4) Apres-midi 2 (15:45 - 17:45)");
		System.out.println("5) Revenir a l'etape precedente");
		System.out.println("0) Revenir au menu principal");

		String input = this.scanner.next();

		Schedule schedule;
		if (input.equals("1")) {
			schedule = Schedule.Morning1;
		} else if (input.equals("2")) {
			schedule = Schedule.Morning2;
		} else if (input.equals("3")) {
			schedule = Schedule.Afternoon1;
		} else if (input.equals("4")) {
			schedule = Schedule.Afternoon2;
		} else if (input.equals("5")) {
			this.addSeance();
			return;
		} else if (input.equals("0")) {
			this.menu();
			return;
		} else {
			System.out.println("Saisie incorrecte. Veuillez reessayer.\n");
			this.addSeance1(year, month, day);
			return;
		}

		Date d = null;
		try {
			d = new Date(year, month, day, schedule);
			this.addSeance2(d);
		} catch (IncorrectDateFormatException e) {
			System.out
					.println("La date est incorrecte. Veuillez en saisir une autre : "
							+ e.getMessage() + "\n");
			this.addSeance();
			return;
		}
	}

	private void addSeance2(Date d) {
		System.out
				.println("Entrer le numero de l'enseignant de cette seance :");

		System.out.println("1) " + t.getHeadTeacher());

		int i = 2;
		for (Teacher e : t.getTeachers()) {
			System.out.println(i + ") " + e);
			i++;
		}

		int input = this.scanner.nextInt();

		Teacher client = null;
		if (input == 1) {
			client = t.getHeadTeacher();
		} else if ((input >= 2) && (input <= t.getTeachers().size() + 2)) {
			client = t.getTeachers().get(input - 2);
		} else {
			System.out.println("Saisie incorrecte. Veuillez reessayer.\n");
			this.addSeance2(d);
		}
		this.addSeance3(d, client);
	}

	private void addSeance3(Date d, Teacher client) {
		System.out.println("Entrez le groupe d'eleve concerne");

		int i = 1;
		for (Group g : t.getStudentsGroups()) {
			System.out.println(i + ") " + g.getId());
			i++;
		}

		int input = -1;
		try {
			input = this.scanner.nextInt();
		} catch (Exception e) {
		}

		Group groups = new Group();

		if ((input >= 1) && (input <= t.getStudentsGroups().size())) {
			groups = t.getStudentsGroups().get(input - 2);
			this.addSeance4(d, client, groups);
		} else {
			System.out.println("Saisie incorrecte. Veuillez reessayer.\n");
			this.addSeance3(d, client);
		}
	}

	private void addSeance4(Date d, Teacher client, Group groups) {
		int nbStudents = groups.getStudents().size();
		LinkedList<Room> availableRooms = Reservation.getAvailableRooms(d,
				nbStudents, this.dc.getRooms(), this.dc.getReservations());

		if (availableRooms.size() == 0) {
			System.out
					.println("Desole, il n'y a aucune salle disponible pour cet effectif a cette horaire.");
			System.out.println("Veuillez choisir un autre horaire");
			this.addSeance();
			return;
		}
		System.out.println("Voici les salles disponibles a cet horaire : ");

		for (Room r : availableRooms) {
			if (r.equals(Reservation.getOptimizedRoom(
					this.dc.getReservations(), this.dc.getRooms(), nbStudents,
					d)))
				System.out.println("\t" + r + " ( salle conseillée )" + "\n");
			else
				System.out.println("\t" + r + "\n");
		}

		System.out.println("\nVeuillez entrez l'id d'une salle");

		String input = this.scanner.next();

		Room room = null;

		for (Room r : availableRooms)
			if (r.getId().toString().equals(input))
				room = r;

		if (room == null) {
			System.err
					.println("Id non reconnu. Veuillez resaisir l'id de la salle choisie.");
			this.addSeance4(d, client, groups);
			return;
		}

		List<Group> l = new LinkedList<Group>();
		l.add(groups);
		Reservation r = room.book(client, d, l, dc.getReservations(), t);

		if (r == null) {
			System.err.println("Votre reservation n'est pas disponible.");
			System.out.println("Retour au menu princpal...");
			this.menu();
			return;
		}

		dc.getReservations().add(r);

		System.out
				.println("Reservation effectuee avec succes. Recapitulatif de votre reservation : ");
		System.out.println(r + "\n");

		this.menu();
	}

	private void deleteSeance() {
		LinkedList<Reservation> reservations = Reservation
				.getReservationsByTeaching(t, this.dc.getReservations());

		if (reservations.size() == 0) {
			System.out
					.println("Il n'y a pas de reservation pour cet enseignement.");
			menu();
			return;
		}

		System.out
				.println("Choisissez le numero de la seance que vous souhaitez enlever ou uniquement \"0\" pour revenir au menu principal : ");

		int reponse2;
		Iterator<Reservation> it = reservations.iterator();
		int j = 1;
		while (it.hasNext()) {
			System.out.println(j + ") " + it.next().getDate());
			j++;
		}

		System.out
				.println("Entrez le numero de la seance qui vous interesse : ");
		reponse2 = Integer.parseInt(scanner.next());

		if (reponse2 == 0) {
			this.menu();
			return;
		}
		;

		if (reponse2 > 0 && reponse2 <= reservations.size())
			this.dc.getReservations().remove((reservations.get(reponse2 - 1)));

		menu();
	}

	private void addTeacher() {
		LinkedList<Teacher> availableTeachers = new LinkedList<Teacher>();

		for (Teacher t : this.dc.getTeachers())
			if (!this.t.getTeachers().contains(t)
					&& !t.equals(this.t.getHeadTeacher()))
				availableTeachers.add(t);

		if (this.dc.getTeachers().size() < 2 || availableTeachers.size() == 0) {
			System.out.println("Il n'y a pas d'autres enseignants !");
			menu();
			return;
		}

		System.out
				.println("Choisissez le numero de l'enseignant que vous souhaitez ajouter ou uniquement \"0\" pour revenir au menu principal : ");
		int reponse2;
		Iterator<Teacher> it = availableTeachers.iterator();
		int j = 1;
		while (it.hasNext()) {
			System.out.println(j + ") " + it.next().getLastName());
			j++;
		}

		System.out
				.println("Entrez le numero de l'enseignant qui vous interesse : ");
		reponse2 = Integer.parseInt(scanner.next());
		if (reponse2 == 0) {
			this.menu();
			return;
		}

		if (reponse2 > 0 && reponse2 <= availableTeachers.size())
			t.getTeachers().addLast((availableTeachers.get(reponse2 - 1)));
		else
			System.out.println("Mauvaise saisie !\n");

		menu();
	}

	private void deleteTeacher() {
		if (this.t.getTeachers().size() < 1) {
			System.out.println("Il n'y a pas d'enseignant a supprimer.\n");
			menu();
			return;
		}

		System.out
				.println("Choisissez le numero de l'enseignant que vous souhaitez enlever ou uniquement \"0\" pour revenir au menu principal : ");
		int reponse2;
		Iterator<Teacher> it = t.getTeachers().iterator();
		int j = 1;
		while (it.hasNext()) {
			System.out.println(j + ") " + it.next().getLastName());
			j++;
		}

		System.out
				.println("Entrez le numero de l'enseignant qui vous interesse : ");
		reponse2 = Integer.parseInt(scanner.next());

		if (reponse2 == 0) {
			this.menu();
			return;
		}

		if (reponse2 > 0 && reponse2 <= t.getTeachers().size())
			t.getTeachers().remove((t.getTeachers().get(reponse2 - 1)));
		else
			System.out.println("Mauvaise saisie !\n");

		menu();
	}

	private void menu() {
		System.out.println("*** Enseignement " + t.getName() + " ***");
		System.out.println("1) Modifier le nom de l'Enseignement");
		System.out.println("2) Ajouter un groupe d'etudiant");
		System.out.println("3) Enlever un groupe d'etudiant");
		System.out.println("4) Ajouter une seance d'un Enseignement");
		System.out.println("5) Enlever une seance d'un Enseignement");
		System.out.println("6) Ajouter un enseignant participant");
		System.out.println("7) Enlever un enseignant participant");
		System.out.println("8) Enregistrer les donnees");
		System.out.println("9) Quitter le programme");

		int reponse = SimulatorHelper.getNextInt(scanner, 1, 9);

		switch (reponse) {
		case 1:
			modifierNomEnseignement();
			break;
		case 2:
			addGroup();
			break;
		case 3:
			deleteGroup();
			break;
		case 4:
			addSeance();
			break;
		case 5:
			deleteSeance();
			break;
		case 6:
			addTeacher();
			break;
		case 7:
			deleteTeacher();
			break;
		case 8:
			this.saveData();
			break;
		default:
			break;
		}
	}
}
